#ifndef _YEP_SCENETEST_DRAGABLE_TEST_HPP
#define _YEP_SCENETEST_DRAGABLE_TEST_HPP

#include "common.hpp"
#include "framework/Entity.hpp"
#include "framework/MouseHandler.hpp"
#include "framework/CollisionHandler.hpp"
#include "framework/FrameHandler.hpp"
#include "framework/DrawHandler.hpp"
#include "framework/MouseEvent.hpp"
#include "framework/CollisionEvent.hpp"
#include "framework/DrawEvent.hpp"

namespace yep
{
/**
 * @brief Tests MouseHandler and CollisionHandler
 **/
class DragableTest: public Entity, public MouseHandler, public CollisionHandler, public FrameHandler, public DrawHandler
{
public:
    DragableTest( const Vector2 &initialPosition ): _initialPosition( initialPosition ),
        _currentPosition( Vector2::ZERO ), _previousPosition( Vector2::ZERO ), _size( 64, 64 ) {}
    ~DragableTest() {}

    bool isInside( Vector2 mousePosition )
    {
        return ( mousePosition.after( getTopLeft() ) || mousePosition == getTopLeft() ) && mousePosition.before( getBottomRight() );
    }

    double getDepth()
    {
        return 0;
    }

    Vector2 getTopLeft()
    {
        return _currentPosition;
    }

    Vector2 getBottomRight()
    {
        return _currentPosition + _size;
    }

    bool collides( CollisionHandler &other )
    {
        if( DragableTest *otherDragable = dynamic_cast<DragableTest *>( &other ) )
        {
            return getTopLeft().before( otherDragable->getBottomRight() ) && getBottomRight().after( otherDragable->getTopLeft() );
        }

        return false;
    }

    void evCreate( Event &event )
    {
        Scene2d &scene( event.getScene() );
        scene.handleCollision( *this );
        scene.handleMouse( *this );
        scene.handleDraw( *this );
        scene.handleFrame( *this );
        _over = false;
        _draging = false;
        _currentPosition = _initialPosition;
        _previousPosition = _initialPosition;
    }

    void evDestroy( Event &event )
    {
        Scene2d &scene( event.getScene() );
        scene.unhandleCollision( *this );
        scene.unhandleMouse( *this );
        scene.unhandleDraw( *this );
        scene.unhandleFrame( *this );
        delete this;
    }

    void evCollision( CollisionEvent &event )
    {
        Vector2 delta( _currentPosition - _previousPosition );
        if(delta == Vector2::ZERO)
            return;
        _currentPosition = _previousPosition;
        Vector2 diAreaion( delta.angle());
        DragableTest &other( dynamic_cast<DragableTest &>( event.getOther() ) );
        unsigned counter = 0;
        do
        {
            _currentPosition += diAreaion;
            ++counter;
        } while( !collides(other) && counter <= 480);
        _currentPosition -= diAreaion;
    }

    void evMouseDown( MouseButtonEvent &event )
    {
        if( event.getButton() == SDL_BUTTON_LEFT )
        {
            _draging = true;
        }

        event.veto();
    }

    void evMouseUp( MouseButtonEvent &event )
    {
        if( event.getButton() == SDL_BUTTON_LEFT )
        {
            _draging = false;
        }

        event.veto();
    }

    void evMouseMove( MouseMoveEvent &event )
    {
        if( _draging )
        {
            _currentPosition += event.getNewPosition() - event.getOldPosition();
        }

        event.veto();
    }

    void evMouseOut( MouseMoveEvent &event )
    {
        _over = false;

        if( _draging )
        {
            _currentPosition += event.getNewPosition() - event.getOldPosition();
        }
        if(!isInside(event.getNewPosition()))
            _draging = false;

        event.veto();
    }

    void evMouseOver( MouseMoveEvent &event )
    {
        _over = true;
        event.veto();
    }

    void evFrameBegin( Event &event )
    {
        _currentPosition = {round(_currentPosition.x), round(_currentPosition.y)};
        _previousPosition = _currentPosition;
    }

    void evDraw( DrawEvent &event )
    {
        Screen &screen( event.getScreen() );

        if( _draging )
        {
            screen.fillRectangle( _currentPosition, _size, Color::DARK_GRAY );
            screen.drawRectangle( _currentPosition, _size, Color::WHITE );
        }
        else if( _over )
        {
            screen.fillRectangle( _currentPosition, _size, Color::DARK_GRAY );
            screen.drawRectangle( _currentPosition, _size, Color::LIGHT_GRAY );
        }
        else
        {
            screen.fillRectangle( _currentPosition, _size, Color::BLACK );
            screen.drawRectangle( _currentPosition, _size, Color::LIGHT_GRAY );
        }
    }

private:
    Vector2 _initialPosition;
    Vector2 _currentPosition;
    Vector2 _previousPosition;
    Vector2 _size;
    bool _draging;
    bool _over;
};

}

#endif // _YEP_SCENETEST_DRAGABLE_TEST_HPP

